package com.ctshk.rpc.order.airexpress.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.CurrencyRateExchangeConstant;
import com.ctshk.common.constant.ElasticSearchConstant;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.constant.SystemConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.dto.payment.CallPayDTO;
import com.ctshk.common.elasticsearch.config.ElasticSearchConfiguration;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.Currency;
import com.ctshk.common.enums.payment.PayCurrency;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.AppReq;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.req.pay.NotifyConsumeReq;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.airexpress.dto.AirportExpressInfoDTO;
import com.ctshk.rpc.airexpress.dto.AirportExpressPriceRemainderDTO;
import com.ctshk.rpc.airexpress.dto.app.TicketNameDTO;
import com.ctshk.rpc.airexpress.req.AirportExpressIncreaseStrategyPriceQueryReq;
import com.ctshk.rpc.airexpress.service.IAirportExpressAppService;
import com.ctshk.rpc.airexpress.service.IAirportExpressService;
import com.ctshk.rpc.booking.req.system.airexpress.add.SupplierOrderSystemAirExpressAddReq;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.iotc.dto.OperateBankPreferenceQueryDTO;
import com.ctshk.rpc.iotc.req.OperateBankConformQueryReq;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.order.airexpress.constants.AirportExpressConstants;
import com.ctshk.rpc.order.airexpress.dto.*;
import com.ctshk.rpc.order.airexpress.dto.app.*;
import com.ctshk.rpc.order.airexpress.dto.elasticsearch.AirportExpressOrderUpLoadDTO;
import com.ctshk.rpc.order.airexpress.dto.mtr.AirportExpressMTRDTO;
import com.ctshk.rpc.order.airexpress.dto.mtr.AirportExpressTicketMTRDTO;
import com.ctshk.rpc.order.airexpress.entity.AirportExpressOrder;
import com.ctshk.rpc.order.airexpress.entity.AirportExpressOrderCollection;
import com.ctshk.rpc.order.airexpress.entity.AirportExpressOrderReceipt;
import com.ctshk.rpc.order.airexpress.entity.AirportExpressOrderTourist;
import com.ctshk.rpc.order.airexpress.enums.AirExpressTouristType;
import com.ctshk.rpc.order.airexpress.enums.MTRProfile;
import com.ctshk.rpc.order.airexpress.mapper.*;
import com.ctshk.rpc.order.airexpress.req.AirportExpressOrderCancelReq;
import com.ctshk.rpc.order.airexpress.req.AirportExpressOrderListReq;
import com.ctshk.rpc.order.airexpress.req.app.AirportExpressOrderAppReq;
import com.ctshk.rpc.order.airexpress.service.AirportExpressOrderMTRService;
import com.ctshk.rpc.order.airexpress.service.AirportExpressService;
import com.ctshk.rpc.order.airexpress.service.IAirportExpressOrderAppService;
import com.ctshk.rpc.payment.enums.PaymentMethod;
import com.ctshk.rpc.payment.service.IPayService;
import com.ctshk.rpc.starvip.dto.start_vip.transaction.TrainIntegralDTO;
import com.ctshk.rpc.starvip.dto.start_vip.user.StarVipCreateOrUpdateDTO;
import com.ctshk.rpc.starvip.req.TransactionIntegralCommonReq;
import com.ctshk.rpc.starvip.req.transaction.StarVipTransactionIntegralReq;
import com.ctshk.rpc.starvip.service.IStarVipBusinessService;
import com.ctshk.rpc.system.constants.Constants;
import com.ctshk.rpc.system.dto.MainDataCurrencyListDTO;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.dto.member.ContactQueryDTO;
import com.ctshk.rpc.system.enums.CrmMemberProductPointsRateEnum;
import com.ctshk.rpc.system.req.DispatchOrderRuleGetUserReq;
import com.ctshk.rpc.system.req.MainDataCurrencyListReq;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.UploadReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberQueryReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberUpdatePointsReq;
import com.ctshk.rpc.system.service.*;
import com.ctshk.rpc.user.dto.AppUserDTO;
import com.ctshk.rpc.user.service.IOrderEsService;
import com.ctshk.rpc.user.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import scala.annotation.meta.param;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * <p>
 * 机场快线订单表 服务实现类
 * </p>
 *
 * @author 叶冠峰
 * @since 2021-02-23
 */
@Slf4j
@DubboService
public class AirportExpressOrderAppServiceImpl extends ServiceImpl<AirportExpressOrderMapper, AirportExpressOrder> implements IAirportExpressOrderAppService {
    @Autowired
    private AirportExpressService airportExpressServiceComponent;
    @Autowired
    AirportExpressOrderMapper airportExpressOrderMapper;
    @Autowired
    AirportExpressOrderCollectionMapper airportExpressOrderCollectionMapper;
    @Autowired
    AirportExpressOrderTouristMapper airportExpressOrderTouristMapper;
    @Autowired
    AirportExpressOrderRefundMapper airportExpressOrderRefundMapper;
    @Autowired
    AirportExpressOrderReceiptMapper airportExpressOrderReceiptMapper;
    @DubboReference
    ISysUserService sysUserService;
    @DubboReference
    IUserService userService;
    @DubboReference
    IAirportExpressService airportExpressService;
    @DubboReference
    IMainDataCurrencyService mainDataCurrencyService;
    @DubboReference
    IOperateBankPreferenceService operateBankPreferenceService;
    @DubboReference
    ICrmMemberService crmMemberService;
    @DubboReference
    IStarVipBusinessService starVipBusinessService;
    @DubboReference
    ISysPermissionService sysPermissionService;
    @DubboReference
    ISupplierOrderService supplierOrderService;
    @DubboReference
    IFileOSSService fileOSSService;
    @DubboReference
    IDispatchOrderRuleService dispatchOrderRuleService;
    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Autowired
    AirPortExpressOrderDetailsMapper airPortExpressOrderDetailsMapper;
    @Autowired
    RedisTemplate<String, Object> redisTemplate;
    @Autowired
    AirportExpressOrderUpLoadMapper airportExpressOrderUpLoadMapper;
    @DubboReference
    private IOrderEsService orderEsService;
    @Autowired
    AirportExpressOrderMTRService airportExpressOrderMTRService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result submit(AirportExpressOrderAppReq airportExpressOrderReq, Long currentUserId, AppReq appReq) {
        log.info("【机场快线订单APP-提交订单】方法入参, data:{}, userId:{}, appReq:{}", JSON.toJSONString(airportExpressOrderReq), currentUserId, JSON.toJSONString(appReq));
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        LocalDate nowLocalDate = LocalDate.now();
        int adultNumber = airportExpressOrderReq.getAdultTicketNumber();
        int childrenNumber = airportExpressOrderReq.getChildrenTicketNumber() == null ? 0 : airportExpressOrderReq.getChildrenTicketNumber();
        int touristNumber = adultNumber + childrenNumber;
        //获取机场快线订单编号
        AirportExpressOrder airportExpressOrder = EntityUtil.copy(airportExpressOrderReq, AirportExpressOrder.class);
        // 获取id
        Long id = SnowflakeIdWorker.nextId();
        try {
            /**
             * 获取销售人，生成销售编号
             */
            Long saleManId = getSaleManId(appReq.getCompanyType());
            UserDTO userDTO = sysUserService.queryCacheUser(saleManId);
            String orderNumber = airportExpressServiceComponent.generatorOrderNumber(userDTO, nowLocalDateTime);
            airportExpressOrder.setOrderNumber(orderNumber);
            airportExpressOrder.setSalesmanId(userDTO.getId());
            airportExpressOrder.setSalesmanName(userDTO.getFullName());
            airportExpressOrder.setSalesmanDeptNumber(userDTO.getDeptNumber());
            // 查询加幅后的价格，售卖类型，余票
            AirportExpressIncreaseStrategyPriceQueryReq airportExpressIncreaseStrategyPriceQueryReq = new AirportExpressIncreaseStrategyPriceQueryReq();
            airportExpressIncreaseStrategyPriceQueryReq.setAirportExpressId(airportExpressOrderReq.getAirportExpressId());
            airportExpressIncreaseStrategyPriceQueryReq.setTouristNumber(touristNumber);
            airportExpressIncreaseStrategyPriceQueryReq.setUserId(userDTO.getId());
            airportExpressIncreaseStrategyPriceQueryReq.setSaleChannelId(Channel.PLATFORM.getCode());
            airportExpressIncreaseStrategyPriceQueryReq.setChannelId(appReq.getChannelId());
            log.info("【机场快线订单APP-提交订单】获取产品价格方法请求, data:{}", airportExpressIncreaseStrategyPriceQueryReq);
            AirportExpressPriceRemainderDTO airportExpressPriceRemainderDTO = airportExpressService.selectPriceRemainderAndLock(airportExpressIncreaseStrategyPriceQueryReq);
            log.info("【机场快线订单APP-提交订单】获取产品价格方法响应, data:{}", airportExpressPriceRemainderDTO);
            if (null != currentUserId) { // 查询C端已登录用户信息
                AppUserDTO appUserDTO = userService.queryCacheUser(currentUserId);
                if (appUserDTO == null) {
                    throw new BusinessException(SystemError.USER_1002);
                }
                airportExpressOrder.setMemberId(appUserDTO.getMemberId());
            }
            //计算订单金额
            BigDecimal orderAmount;
            BigDecimal childrenPrice = null;
            BigDecimal adultPrice = airportExpressPriceRemainderDTO.getAdultPrice();
            BigDecimal adultPriceTotal = adultPrice.multiply(new BigDecimal(adultNumber));
            if (childrenNumber > 0) {
                childrenPrice = airportExpressPriceRemainderDTO.getChildrenPrice();
                BigDecimal childrenPriceTotal = childrenPrice.multiply(new BigDecimal(childrenNumber));
                orderAmount = adultPriceTotal.add(childrenPriceTotal);
            } else {
                orderAmount = adultPriceTotal;
            }
            /**
             * 根据总价计算应收金额，减去会员积分和优惠券
             */
            BigDecimal receivableAmount = buildReceivableAmount(airportExpressOrder, orderAmount);
            // 计算有效期
            airportExpressOrder.setEffectiveTime(nowLocalDate.plusDays(92)); //固定92天有效期
            // 计算付款到期时间,+30分钟
            airportExpressOrder.setPayExpireDate(nowLocalDateTime.plusMinutes(30)); //固定30分钟
            // 获取门市汇率 并设置
            airportExpressOrder.setAdultCostPrice(airportExpressPriceRemainderDTO.getAdultCostPrice());
            airportExpressOrder.setAdultCostCurrencyId(Currency.HKD.getCode());
            airportExpressOrder.setAdultCostCurrency(Currency.HKD.getCurrency());
            airportExpressOrder.setAdultCostExchangeRate(BigDecimal.ONE);
            airportExpressOrder.setChildrenCostPrice(airportExpressPriceRemainderDTO.getChildrenCostPrice());
            airportExpressOrder.setChildrenCostCurrencyId(Currency.HKD.getCode());
            airportExpressOrder.setChildrenCostCurrency(Currency.HKD.getCurrency());
            airportExpressOrder.setChildrenCostExchangeRate(BigDecimal.ONE);
            //
            airportExpressOrder.setId(id);
            airportExpressOrder.setOrderAmount(orderAmount);
            airportExpressOrder.setTicketTypeName(airportExpressPriceRemainderDTO.getTicketTypeNameCn());
            airportExpressOrder.setReceivableAmount(receivableAmount);
            airportExpressOrder.setNumber(touristNumber);
            airportExpressOrder.setSource(appReq.getOrderSource());
            airportExpressOrder.setAdultPrice(adultPrice);
            airportExpressOrder.setChildrenPrice(childrenPrice);
            airportExpressOrder.setContactName(airportExpressOrder.getSurname() + airportExpressOrder.getName());
            airportExpressOrder.setPaymentStatus(OrderPaymentStatus.UN_PAYMENT.getCode()); //未付款
            airportExpressOrder.setScheduledStatus(null);
            airportExpressOrder.setCancelStatus(null);
            airportExpressOrder.setSalesmanId(userDTO.getId());
            airportExpressOrder.setSalesmanName(userDTO.getFullName());
            airportExpressOrder.setIsDeleted(IsDeletedCode.NO.getCode());
            airportExpressOrder.setCreateId(userDTO.getId());
            airportExpressOrder.setGmtCreate(nowLocalDateTime);
            airportExpressOrder.setModifiedId(userDTO.getId());
            airportExpressOrder.setGmtModified(nowLocalDateTime);
            airportExpressOrder.setUserId(airportExpressOrderReq.getUserId());
            //新增收据记录
            if (StringUtils.isNotBlank(airportExpressOrderReq.getReceiptTitle())) {
                insertReceipt(airportExpressOrder, userDTO, nowLocalDateTime);
            }
            airportExpressOrderMapper.insert(airportExpressOrder);
            // 启动定时任务
            airportExpressServiceComponent.startScheduleTask(id);
        } catch (BusinessException e) {
            log.error("【机场快线订单APP-提交订单】提交订单失败,error:{}", e.getMessage(), e);
            throw e;
        } catch (Exception e) {
            log.error("【机场快线订单APP-提交订单】系统异常,error:{}", e.getMessage(), e);
            throw e;
        }

        return Result.success(id);
    }

    /**
     * 获取销售人并生成销售编号
     *
     * @param companyType
     */
    private Long getSaleManId(String companyType) {
        DispatchOrderRuleGetUserReq dispatchOrderRuleGetUserReq = new DispatchOrderRuleGetUserReq();
        dispatchOrderRuleGetUserReq.setBusinessTypeId(SystemBusinessType.AIR_EXPRESS.getCode());
        dispatchOrderRuleGetUserReq.setCompanyType(companyType);
        Result<Long> result = dispatchOrderRuleService.getDispatchUserId(dispatchOrderRuleGetUserReq);
        if (!result.isSuccess()) {
            log.error("【机场快线APP-提交订单】获取销售人失败:{},msg:{}", result.getCode(), result.getMsg());
            throw new BusinessException(SystemError.getDefined(result.getCode()));
        }
        return result.getData();
    }

    /**
     * 根据总价计算应收价格，减去会员积分和优惠券
     *
     * @param airportExpressOrder
     * @param orderAmount
     * @return 应收金额
     */
    private BigDecimal buildReceivableAmount(AirportExpressOrder airportExpressOrder, BigDecimal orderAmount) {
        BigDecimal receivableAmount = new BigDecimal(orderAmount.toString());
        //计算应收价格-是否使用积分
        if (Objects.equals(airportExpressOrder.getIfMember(), AirportExpressConstants.IF_MEMBER_YES)) {
            // 获取积分可抵扣金额
            StarVipTransactionIntegralReq starVipTransactionIntegralReq = new StarVipTransactionIntegralReq();
            starVipTransactionIntegralReq.setMemberId(airportExpressOrder.getMemberId());
            starVipTransactionIntegralReq.setReceivableAmount(receivableAmount);
            BigDecimal exchangeRate = mainDataCurrencyService.getExchangeRate(String.valueOf(Currency.CNY.getCurrency()), CurrencyRateExchangeConstant.CRM_EXCHANGE_RATE_);
            starVipTransactionIntegralReq.setExchangeRate(exchangeRate);
            log.info("【机场快线APP-提交订单】查询可用积分和金额信息请求, data：{}", JSON.toJSONString(starVipTransactionIntegralReq));
            TrainIntegralDTO trainIntegralDTO = starVipBusinessService.queryIntegralAndHkd(starVipTransactionIntegralReq);
            log.info("【机场快线APP-提交订单】查询可用积分和金额信息响应, data：{}", JSON.toJSONString(trainIntegralDTO));
            BigDecimal hkd = trainIntegralDTO.getDeduction();
            receivableAmount = receivableAmount.subtract(hkd);
            if (receivableAmount.compareTo(BigDecimal.ZERO) == -1) {
                // 总价减去积分价后为负数，不予许提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
            }
            airportExpressOrder.setUsingPoints(Math.toIntExact(trainIntegralDTO.getAvailable()));
        }
        //计算应收价格-计算推广码（优惠券）, API产品没有推广码、银联优惠业务
        if (airportExpressOrder.getCouponId() != null) {
            // do something 推广码接口未写完，等待中
            /*OperatePromotionConformReq operatePromotionConformReq = new OperatePromotionConformReq();
            operatePromotionConformReq.setActivityCode(airportExpressOrder.getCouponId().toString());
            operatePromotionConformReq.setTotalPaidIn(airportExpressOrder.getOrderAmount());
            operatePromotionConformReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            operatePromotionConformReq.setRelationId(airportExpressOrder.getAirportExpressId());
            operatePromotionConformReq.setChannelId(airportExpressOrder.getSource().longValue());
            operatePromotionConformReq.setUserId(airportExpressOrder.getModifiedId());
            Result<OperatePromotionQueryDTO> operatePromotionQueryDTOResult = operatePromotionService.queryConform(operatePromotionConformReq);
            if (operatePromotionQueryDTOResult.getCode() != 0) {
                //该订单不满足使用条件
                SystemError systemError = SystemError.getDefined(operatePromotionQueryDTOResult.getCode());
                throw new BusinessException(systemError);
            }
            OperatePromotionQueryDTO data = operatePromotionQueryDTOResult.getData();
            receivableAmount = receivableAmount.subtract(data.getReductionAmount());
            if (receivableAmount.compareTo(BigDecimal.ZERO) == -1) {
                // 总价减去积分价后为负数，不予许提交
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
            }*/
        }
        return receivableAmount;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result payment(NotifyConsumeReq notifyConsumeReq) throws Exception {
        log.info("【机场快线订单APP-支付订单】方法入参:{}", JSON.toJSONString(notifyConsumeReq));
        try {
            AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(new QueryWrapper<AirportExpressOrder>().lambda()
                    .eq(AirportExpressOrder::getOrderNumber, notifyConsumeReq.getOrderNumber())
                    .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode()));
            if (airportExpressOrder == null) {
                //订单不存在
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
            }
            LocalDateTime nowLocalDateTime = LocalDateTime.now();
            if (nowLocalDateTime.isAfter(airportExpressOrder.getPayExpireDate())) {
                // 支付超时
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60001);
            }
            UserDTO userDTO = sysUserService.queryCacheUser(airportExpressOrder.getSalesmanId());
            airportExpressOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
            airportExpressOrder.setModifiedId(userDTO.getId());
            airportExpressOrder.setGmtModified(nowLocalDateTime);
            // 计算支付总金额和支付记录
            BigDecimal readyMoney = notifyConsumeReq.getAmount();//实收金额(港币)
            MainDataCurrencyListDTO currencyDTO = getExchangeRateByName(notifyConsumeReq.getCurrency());
            BigDecimal exchangeRate = currencyDTO.getMarketExchangeRate();
            BigDecimal standardAmount = readyMoney.multiply(exchangeRate); // 计算本位币金额
            PaymentMethod paymentMethod = PaymentMethod.getByCode(notifyConsumeReq.getPaymentMethod());

            AirportExpressOrderCollection airportExpressOrderCollection = new AirportExpressOrderCollection();
            String paymentNumber = airportExpressServiceComponent.generatorPaymentNumber(nowLocalDateTime);
            airportExpressOrderCollection.setId(SnowflakeIdWorker.nextId());
            airportExpressOrderCollection.setOrderId(airportExpressOrder.getId());
            airportExpressOrderCollection.setCollectionNumber(paymentNumber);
            airportExpressOrderCollection.setCollectionAmount(readyMoney);
            airportExpressOrderCollection.setCurrencyId(Currency.HKD.getCode());
            airportExpressOrderCollection.setCurrency(Currency.HKD.getCurrency());
            airportExpressOrderCollection.setCollectionWayId(paymentMethod.getPayRefundMethodId()); //付款方式
            airportExpressOrderCollection.setCollectionWay(paymentMethod.getName());   //付款方式
            airportExpressOrderCollection.setPayer(notifyConsumeReq.getPaymentAccount()); //付款账号
            airportExpressOrderCollection.setExchangeRate(exchangeRate);// 汇率
            airportExpressOrderCollection.setStandardAmount(standardAmount);//本位币金额
            airportExpressOrderCollection.setStatus(OrderCollectionStatus.UN_REJECT.getCode());
            airportExpressOrderCollection.setSalerId(userDTO.getId());
            airportExpressOrderCollection.setSalerName(userDTO.getFullName());
            airportExpressOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
            airportExpressOrderCollection.setCreateId(userDTO.getId());
            airportExpressOrderCollection.setGmtCreate(nowLocalDateTime);
            airportExpressOrderCollection.setModifiedId(userDTO.getId());
            airportExpressOrderCollection.setGmtModified(nowLocalDateTime);

            /**
             * 港铁下单
             */
            AirportExpressMTRDTO airportExpressMTRDTO = airportExpressOrderMTRService.buildAndCreateMtrOrder(airportExpressOrder);
            if (airportExpressMTRDTO == null || CollectionUtils.isEmpty(airportExpressMTRDTO.getTicket())) {
                // 下单失败
                airportExpressOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_FAIL.getCode());
                airportExpressOrderMapper.updateById(airportExpressOrder);
                return Result.failed(SystemError.AIREXPRESS_ORDER_60017);
            }

            /**
             * 上传二维码图片到阿里云
             */
            List<UploadReq> uploadReqList = buildUploadReq(airportExpressOrder.getId(), airportExpressMTRDTO);
            fileOSSService.uploadBatch(uploadReqList);

            /**
             * 港铁下单成功后
             * 1.减去使用的会员积分，增加消费的产生会员积分
             * 2.减去使用的优惠券(机场快线无优惠券业务)
             * 3.新增会员积分、优惠券的收款记录
             */
            useAndUpdateCrmMemberPoints(airportExpressOrder);

            // 机场快线车票信息列表
            List<AirportExpressOrderTourist> airportExpressOrderTouristList = new ArrayList<>();
            airportExpressMTRDTO.getTicket().forEach(ticketMtrDto -> {
                AirportExpressOrderTourist airportExpressOrderTourist = new AirportExpressOrderTourist();
                airportExpressOrderTourist.setId(SnowflakeIdWorker.nextId());
                airportExpressOrderTourist.setOrderId(airportExpressOrder.getId());
                airportExpressOrderTourist.setThirdTicketNumber(ticketMtrDto.getTid());
                airportExpressOrderTourist.setThirdTicketQrCode(ticketMtrDto.getQrcode());
                String qrCodeUrl = Constants.FILE_HOST + ticketMtrDto.getFullName();
                airportExpressOrderTourist.setThirdTicketQrCodeUrl(qrCodeUrl);
                //设置旅客类型
                if (ticketMtrDto.getProfile().equals(MTRProfile.ADULT.getCode())) {
                    airportExpressOrderTourist.setTouristType(AirExpressTouristType.ADULT.getCode());
                }
                if (ticketMtrDto.getProfile().equals(MTRProfile.CHILDREN.getCode())) {
                    airportExpressOrderTourist.setTouristType(AirExpressTouristType.CHILDREN.getCode());
                }
                airportExpressOrderTourist.setIsDeleted(IsDeletedCode.NO.getCode());
                airportExpressOrderTourist.setCreateId(userDTO.getId());
                airportExpressOrderTourist.setGmtCreate(nowLocalDateTime);
                airportExpressOrderTourist.setModifiedId(userDTO.getId());
                airportExpressOrderTourist.setGmtModified(nowLocalDateTime);
                airportExpressOrderTouristList.add(airportExpressOrderTourist);
            });
            /**
             * 生成财务记录
             */
            log.info("【机场快线订单】生成供应商预订，查询机场快线信息, id:{}", airportExpressOrder.getAirportExpressId());
            AirportExpressInfoDTO airportExpressInfoDTO = airportExpressService.selectInfo(airportExpressOrder.getAirportExpressId());
            log.info("【机场快线订单】生成供应商预订，查询机场快线信息, info:{}", JSON.toJSONString(airportExpressInfoDTO));
            /**
             * 生成供应预订单
             */
            UserDTO chargeUser = sysUserService.queryCacheUser(airportExpressInfoDTO.getChargePersonId()); // 查询负责人
            SupplierOrderSystemAirExpressAddReq supplierOrderSystemAirExpressAddReq = airportExpressServiceComponent.generatorSupplierBooking(airportExpressOrder, chargeUser,
                    airportExpressMTRDTO, airportExpressInfoDTO, nowLocalDateTime);
            supplierOrderService.addSystemAirExpress(supplierOrderSystemAirExpressAddReq, airportExpressOrder.getSalesmanId());

            // 保存订单,生成查询单号
            String inquiryNumber = airportExpressServiceComponent.generatorInquiryNumber();
            airportExpressOrder.setInquiryNumber(inquiryNumber);
            airportExpressOrder.setThirdOrderNumber(airportExpressMTRDTO.getRefNo());
            airportExpressOrder.setScheduledStatus(OrderScheduledStatus.RESERVE_SUCCESS.getCode());
            airportExpressOrderTouristMapper.insertBatchSomeColumn(airportExpressOrderTouristList);
            airportExpressOrderCollectionMapper.insert(airportExpressOrderCollection);
            airportExpressOrderMapper.updateById(airportExpressOrder);
        } catch (BusinessException e) {
            log.error("【机场快线订单APP-回调支付】唤起支付失败失败,error:{}", e.getMessage(), e);
            throw e;
        } catch (Exception e) {
            log.error("【机场快线订单APP-回调支付】系统异常,error:{}", e.getMessage(), e);
            throw e;
        }
        return Result.success();
    }

    /**
     * 上传二维码图片
     *
     * @param airportExpressMTRDTO
     * @return
     */
    private List<UploadReq> buildUploadReq(Long id, AirportExpressMTRDTO airportExpressMTRDTO) {
        List<UploadReq> uploadReqList = new ArrayList<>();
        Base64.Decoder mimeDecoder = Base64.getMimeDecoder();
        for (int i = 0; i < airportExpressMTRDTO.getTicket().size(); i++) {
            AirportExpressTicketMTRDTO ticket = airportExpressMTRDTO.getTicket().get(i);
            UploadReq uploadReq = new UploadReq();
            byte[] bytes = mimeDecoder.decode(ticket.getQrcode().getBytes(StandardCharsets.UTF_8));
            uploadReq.setId(ticket.getTid());
            uploadReq.setBytes(bytes);
            // AIR_EXPRESS-qr-123456789-i.png
            String fullName = SystemBusinessType.AIR_EXPRESS + "-qr-" + id + "-" + i + ".png";
            uploadReq.setFullName(fullName);
            uploadReqList.add(uploadReq);
            ticket.setFullName(fullName);
        }
        return uploadReqList;
    }

    private int insertReceipt(AirportExpressOrder airportExpressOrder, UserDTO userDTO, LocalDateTime nowLocalDateTime) {
        //生成收据单号
        String receiptNumber = airportExpressServiceComponent.generatorReceiptNumber(userDTO, nowLocalDateTime);
        AirportExpressOrderReceipt airportExpressOrderReceipt = new AirportExpressOrderReceipt();
        airportExpressOrderReceipt.setId(SnowflakeIdWorker.nextId());
        airportExpressOrderReceipt.setOrderId(airportExpressOrder.getId());
        airportExpressOrderReceipt.setReceiptNo(receiptNumber);
        airportExpressOrderReceipt.setTransactionTime(nowLocalDateTime);
        airportExpressOrderReceipt.setBranch(userDTO.getDept());
        airportExpressOrderReceipt.setGuest(airportExpressOrder.getContactName());
        airportExpressOrderReceipt.setPhone(airportExpressOrder.getContactMobileAreaCode() + "-" + airportExpressOrder.getContactMobile());
        airportExpressOrderReceipt.setIsDeleted(IsDeletedCode.NO.getCode());
        airportExpressOrderReceipt.setCreateId(userDTO.getId());
        airportExpressOrderReceipt.setGmtCreate(nowLocalDateTime);
        airportExpressOrderReceipt.setModifiedId(userDTO.getId());
        airportExpressOrderReceipt.setGmtModified(nowLocalDateTime);
        return airportExpressOrderReceiptMapper.insert(airportExpressOrderReceipt);
    }

    /**
     * 使用和更新crm会员积分
     *
     * @param airportExpressOrder
     */
    private void useAndUpdateCrmMemberPoints(AirportExpressOrder airportExpressOrder) {
        // 更新CRM会员积分记录
        log.info("【机场快线订单】更新会员信息,使用积分:{}", airportExpressOrder.getIfMember());
        if (Objects.equals(AirportExpressConstants.IF_MEMBER_YES, airportExpressOrder.getIfMember())) {
            TransactionIntegralCommonReq transactionIntegralCommonReq = new TransactionIntegralCommonReq();
            transactionIntegralCommonReq.setMemberId(airportExpressOrder.getMemberId());
            transactionIntegralCommonReq.setTransactionType(1);
            transactionIntegralCommonReq.setOrderNumber(airportExpressOrder.getOrderNumber());
            transactionIntegralCommonReq.setSystemBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
            transactionIntegralCommonReq.setUsePoints(new BigDecimal(airportExpressOrder.getUsingPoints()));
            transactionIntegralCommonReq.setReceivableAmount(airportExpressOrder.getReceivableAmount());
            transactionIntegralCommonReq.setCurrency(Currency.HKD.getCurrency());
            transactionIntegralCommonReq.setOrderSource(airportExpressOrder.getSource());
            transactionIntegralCommonReq.setUserId(airportExpressOrder.getUserId());
            transactionIntegralCommonReq.setOrderId(airportExpressOrder.getId());
            log.info("【机场快线APP订单服务-更新会员信息】积分交易请求, data:{}", JSON.toJSONString(transactionIntegralCommonReq));
            Result result = starVipBusinessService.transactionIntegralCommon(transactionIntegralCommonReq);
            log.info("【机场快线APP订单服务-更新会员信息】积分交易响应, data:{}", JSON.toJSONString(result));
            if (!result.isSuccess()) {
                throw new BusinessException(SystemError.STAR_VIP_20006);
            }
        }
        // 机场快线无优惠券业务
        /*if (airportExpressOrder.getCouponId() != null) {
        }*/
    }

    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private MainDataCurrencyListDTO getExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = mainDataCurrencyService.list(mainDataCurrencyListReq);
        if (CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0);
    }


    @Override
    public AirportExpressOrderCacheDTO list(AirportExpressOrderListReq airportExpressOrderListReq) {
        //权限控制
        if (airportExpressOrderListReq.getMenuId() == null || airportExpressOrderListReq.getUserId() == null) {
            throw new BusinessException(SystemError.USER_1001);
        }
        Result<List<Long>> permission = sysPermissionService.queryPermission(airportExpressOrderListReq.getMenuId(), airportExpressOrderListReq.getUserId());
        if (!permission.isSuccess()) {
            throw new BusinessException(SystemError.USER_1001);
        }
        List<Long> userList = permission.getData();
        if (CollectionUtils.isEmpty(userList)) {
            return new AirportExpressOrderCacheDTO(new ArrayList<>(), 0, 1, 10);
        }

        // 构建查询条件
        SearchRequest searchRequest = buildSearchRequset(airportExpressOrderListReq, userList);
        AirportExpressOrderPageDTO result = null;
        return null;
        /*try {
            // 执行查询
            SearchResponse response = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            // 构建查询结果
            return buildSearchResult(response, airportExpressOrderListReq);
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }*/

        /*
           加入缓存，逻辑调整，暂时留着备用
        Page<AirportExpressOrder> airportExpressOrderPage = new Page<>(airportExpressOrderListReq.getPageNo(), airportExpressOrderListReq.getPageSize());
        QueryWrapper<AirportExpressOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(airportExpressOrderListReq.getOrderNumber() != null, AirportExpressOrder::getOrderNumber, airportExpressOrderListReq.getOrderNumber());
        queryWrapper.lambda().like(StringUtils.isNotBlank(airportExpressOrderListReq.getTicketTypeName()), AirportExpressOrder::getTicketTypeName, airportExpressOrderListReq.getTicketTypeName());
        queryWrapper.lambda().eq(airportExpressOrderListReq.getPaymentStatus() != null, AirportExpressOrder::getPaymentStatus, airportExpressOrderListReq.getPaymentStatus());
        queryWrapper.lambda().eq(airportExpressOrderListReq.getScheduledStatus() != null, AirportExpressOrder::getScheduledStatus, airportExpressOrderListReq.getScheduledStatus());
        queryWrapper.lambda().ge(airportExpressOrderListReq.getFromGmtCreate() != null, AirportExpressOrder::getGmtCreate, airportExpressOrderListReq.getFromGmtCreate());
        queryWrapper.lambda().le(airportExpressOrderListReq.getToGmtCreate() != null, AirportExpressOrder::getGmtCreate, airportExpressOrderListReq.getToGmtCreate());
        queryWrapper.lambda().like(StringUtils.isNotBlank(airportExpressOrderListReq.getContactName()), AirportExpressOrder::getContactName, airportExpressOrderListReq.getContactName());
        queryWrapper.lambda().eq(airportExpressOrderListReq.getSource() != null, AirportExpressOrder::getSource, airportExpressOrderListReq.getSource());
        queryWrapper.lambda().like(StringUtils.isNotBlank(airportExpressOrderListReq.getSalesmanName()), AirportExpressOrder::getSalesmanName, airportExpressOrderListReq.getSalesmanName());
        queryWrapper.lambda().in(AirportExpressOrder::getCreateId, userList);
        queryWrapper.lambda().orderByDesc(AirportExpressOrder::getGmtCreate);
        Page<AirportExpressOrder> iPage = airportExpressOrderMapper.selectPage(airportExpressOrderPage, queryWrapper);
        List<AirportExpressOrder> records = iPage.getRecords();
        if (CollectionUtils.isEmpty(result)) {
            return new PageResponse<>(new ArrayList<>(), iPage.getCurrent() == 1, iPage.getTotal() <= (iPage.getCurrent() * iPage.getSize()), iPage.getTotal(), iPage.getCurrent(), iPage.getSize());
        }
        List<AirportExpressOrderPageDTO> airportExpressOrderQueryDTOList = EntityUtil.copyList(result, AirportExpressOrderPageDTO.class);
        */

    }

    @Override
    public Result<AppQueryPayResultDTO> queryPayResultInfo(Long id) {
        AppQueryPayResultDTO appQueryPayResultDTO = null;
        try {
            AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(Wrappers.<AirportExpressOrder>lambdaQuery()
                    .eq(AirportExpressOrder::getId, id)
                    .select(AirportExpressOrder::getId, AirportExpressOrder::getAirportExpressId, AirportExpressOrder::getPaymentStatus,
                            AirportExpressOrder::getScheduledStatus, AirportExpressOrder::getOrderNumber, AirportExpressOrder::getInquiryNumber));
            if (airportExpressOrder == null) {
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
            }
            appQueryPayResultDTO = EntityUtil.copy(airportExpressOrder, AppQueryPayResultDTO.class);

            TicketNameDTO ticketNameDTO = airportExpressService.selectTicketNameById(airportExpressOrder.getAirportExpressId());
            appQueryPayResultDTO.setTicketTypeNameCn(ticketNameDTO.getTicketTypeNameCn());
            appQueryPayResultDTO.setTicketTypeNameEn(ticketNameDTO.getTicketTypeNameEn());
            List<AirportExpressOrderCollection> airportExpressOrderCollections = airportExpressOrderCollectionMapper.selectList(new QueryWrapper<AirportExpressOrderCollection>().lambda()
                    .eq(AirportExpressOrderCollection::getOrderId, airportExpressOrder.getId())
                    .eq(AirportExpressOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode()));
            if (CollectionUtils.isNotEmpty(airportExpressOrderCollections)) {
                AirportExpressOrderCollection airportExpressOrderCollection = airportExpressOrderCollections.get(0);
                String collectionWay = airportExpressOrderCollection.getCollectionWay();
                appQueryPayResultDTO.setPaymentMethod(collectionWay);
                appQueryPayResultDTO.setPaymentDateTime(airportExpressOrderCollection.getGmtCreate());
            }
            // 构建支付结果
            if (Objects.equals(airportExpressOrder.getPaymentStatus(), OrderPaymentStatus.ALREADY_PAYMENT) &&
                    Objects.equals(airportExpressOrder.getScheduledStatus(), OrderScheduledStatus.RESERVE_SUCCESS)) {
                appQueryPayResultDTO.setPaymentResult(SystemConstants.BUSINESS_SUCCESS);
            } else {
                appQueryPayResultDTO.setPaymentResult(SystemConstants.BUSINESS_FAIL);
            }
        } catch (BusinessException e) {
            log.error("【机场快线订单APP-查询支付结果】查询失败,error:{}", e.getMessage(), e);
            throw e;
        } catch (Exception e) {
            log.error("【机场快线订单APP-查询支付结果】系统异常,error:{}", e.getMessage(), e);
            throw e;
        }
        return Result.success(appQueryPayResultDTO);
    }

    @Override
    public Result<AppQueryPayResultPcDTO> queryPayResultInfoPc(Long id) {
        AppQueryPayResultPcDTO appQueryPayResultPcDTO = null;
        try {
            AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(Wrappers.<AirportExpressOrder>lambdaQuery()
                    .eq(AirportExpressOrder::getId, id)
                    .select(AirportExpressOrder::getId, AirportExpressOrder::getAirportExpressId, AirportExpressOrder::getPaymentStatus,
                            AirportExpressOrder::getScheduledStatus, AirportExpressOrder::getOrderNumber, AirportExpressOrder::getInquiryNumber,
                            AirportExpressOrder::getEffectiveTime, AirportExpressOrder::getReceivableAmount));
            if (airportExpressOrder == null) {
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
            }
            appQueryPayResultPcDTO = EntityUtil.copy(airportExpressOrder, AppQueryPayResultPcDTO.class);

            TicketNameDTO ticketNameDTO = airportExpressService.selectTicketNameById(airportExpressOrder.getAirportExpressId());
            appQueryPayResultPcDTO.setTicketTypeNameCn(ticketNameDTO.getTicketTypeNameCn());
            appQueryPayResultPcDTO.setTicketTypeNameEn(ticketNameDTO.getTicketTypeNameEn());
            List<AirportExpressOrderCollection> airportExpressOrderCollections = airportExpressOrderCollectionMapper.selectList(new QueryWrapper<AirportExpressOrderCollection>().lambda()
                    .eq(AirportExpressOrderCollection::getOrderId, airportExpressOrder.getId())
                    .eq(AirportExpressOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode()));
            if (CollectionUtils.isNotEmpty(airportExpressOrderCollections)) {
                AirportExpressOrderCollection airportExpressOrderCollection = airportExpressOrderCollections.get(0);
                String collectionWay = airportExpressOrderCollection.getCollectionWay();
                appQueryPayResultPcDTO.setPaymentMethod(collectionWay);
                appQueryPayResultPcDTO.setPaymentDateTime(airportExpressOrderCollection.getGmtCreate());
            }
            // 构建支付结果
            /*if (Objects.equals(airportExpressOrder.getPaymentStatus(), OrderPaymentStatus.ALREADY_PAYMENT) &&
                    Objects.equals(airportExpressOrder.getScheduledStatus(), OrderScheduledStatus.RESERVE_SUCCESS)) {
                appQueryPayResultPcDTO.setPaymentResult(SystemConstants.BUSINESS_SUCCESS);
            } else {
                appQueryPayResultPcDTO.setPaymentResult(SystemConstants.BUSINESS_FAIL);
            }*/
        } catch (BusinessException e) {
            log.error("【机场快线订单APP-查询支付结果】查询失败,error:{}", e.getMessage(), e);
            throw e;
        } catch (Exception e) {
            log.error("【机场快线订单APP-查询支付结果】系统异常,error:{}", e.getMessage(), e);
            throw e;
        }
        return Result.success(appQueryPayResultPcDTO);
    }

    /**
     * 构建检索结果
     *
     * @param response 检索响应
     * @param param    前端请求参数，用来获取分页信息
     * @return
     */
    private AirportExpressOrderCacheDTO buildSearchResult(SearchResponse response, AirportExpressOrderListReq param) {
        // 检索到的命中记录
        SearchHits hits = response.getHits();

        // 提取检索到的记录
        SearchHit[] searchHits = hits.getHits();
        List<AirportExpressOrderDTO> orderList = null;
        if (searchHits != null && searchHits.length > 0) {
            orderList = new ArrayList<>();
            for (SearchHit hit : searchHits) {
                String source = hit.getSourceAsString();
                // 将命中记录反序列化
                AirportExpressOrderDTO airportExpressOrderDTO = JSON.parseObject(source, AirportExpressOrderDTO.class);
                orderList.add(airportExpressOrderDTO);
            }
        }

        // 命中的记录总数
        long value = hits.getTotalHits().value;
        AirportExpressOrderCacheDTO result = new AirportExpressOrderCacheDTO();
        result.setList(orderList);
        if (value > 0) {
            // 计算总页数
            int totalPages = (int) (value % param.getPageSize() == 0 ? value / param.getPageSize() : ((value / param.getPageSize() + 1)));
            result.setTotalPages(totalPages);
            // 页码
            result.setPageNum(param.getPageNo() == null ? 1 : param.getPageNo());
        }

        return result;
    }

    /**
     * 订单详情 - es - 初始化
     *
     * @return
     */
    @Override
    public Result airExpressOrderDetailsInit() {
        // 删除旧数据
        airPortExpressOrderDetailsMapper.deleteAll();

        // 构建缓存数据
        List<AirportExpressOrderUpLoadDTO> airportExpressOrderUpLoadDTOS = buildData(null, null);

        // 上架
        return up(airportExpressOrderUpLoadDTOS, LocalDateTime.now());
    }

    /**
     * 机场快线-订单详情-缓存上架
     *
     * @param ids
     * @return
     */
    @Override
    public Result airExpressOrderDetailsUpLoad(List<Long> ids) {
        return up(buildData(ids, getUpdateTime()), LocalDateTime.now());
    }

    /**
     * 构建es数据
     *
     * @param ids
     * @return
     */
    private List<AirportExpressOrderUpLoadDTO> buildData(List<Long> ids, LocalDateTime now) {
        LambdaQueryWrapper<AirportExpressOrder> wrapper = Wrappers.<AirportExpressOrder>lambdaQuery().eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode());
        wrapper.ge(now != null, AirportExpressOrder::getGmtModified, now);
        wrapper.in(ids != null && ids.size() > 0, AirportExpressOrder::getId, ids);
        List<AirportExpressOrder> airportExpressOrders = baseMapper.selectList(wrapper);
        return EntityUtil.copyList(airportExpressOrders, AirportExpressOrderUpLoadDTO.class);
    }

    /**
     * 机场快线-订单中心-订单详情-缓存更新
     *
     * @param ids
     * @return
     */
    @Override
    public Result cacheUpdate(List<Long> ids) {
        /*
        更换更新方式，此方式暂时留着备用
        BulkRequest bulkRequest = new BulkRequest();
        try {
            Assist.forEach(airportExpressOrderUpLoadDTOS,item -> {
                String jsonString = JSON.toJSONString(item);
                UpdateRequest updateRequest = new UpdateRequest(ElasticSearchConstant.AIR_EXPRESS_ORDER_DETAILS_INDEX, item.getId().toString())
                        .doc(jsonString, XContentType.JSON);
                bulkRequest.add(updateRequest);
            });
            restHighLevelClient.bulk(bulkRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
        } catch (IOException e) {
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        */

        airportExpressOrderUpLoadMapper.saveAll(buildData(ids, null));
        return Result.success();
    }

    /**
     * 机场快线-订单中心-订单详情-按照订单id删除缓存
     *
     * @param ids
     * @return
     */
    @Override
    public Result cacheDelete(List<Long> ids) {
        /*  调整使用spring-data方法，高级客户端方式备用
        BulkRequest bulkRequest = new BulkRequest();
        try {
            ids.forEach(item -> {
                DeleteRequest deleteRequest = new DeleteRequest(ElasticSearchConstant.AIR_EXPRESS_ORDER_DETAILS_INDEX, item.toString());
                bulkRequest.add(deleteRequest);
            });
            restHighLevelClient.bulk(bulkRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }*/

        List<AirportExpressOrderUpLoadDTO> dels = new ArrayList<>();
        ids.forEach(id -> dels.add(new AirportExpressOrderUpLoadDTO().setId(id)));
        airPortExpressOrderDetailsMapper.deleteAll();
        return Result.success();
    }

    /**
     * 机场快线-订单中心-订单详情-删除缓存索引
     *
     * @return
     */
    @Override
    public Result cacheDeleteAll() {
        try {
            restHighLevelClient.indices().delete(new DeleteIndexRequest(ElasticSearchConstant.AIR_EXPRESS_ORDER_DETAILS_INDEX), ElasticSearchConfiguration.COMMON_OPTIONS);
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }
        return Result.success();
    }

    public MyAirportExpressOrderDTO buildEsOrderDTO(Long orderId) {
        AirportExpressOrder airportExpressOrder = baseMapper.selectById(orderId);
        MyAirportExpressOrderDTO orderDTO = EntityUtil.copy(airportExpressOrder, MyAirportExpressOrderDTO.class);

        AirportExpressInfoDTO airportExpressInfoDTO = airportExpressService.selectInfo(orderDTO.getAirportExpressId());
        orderDTO.setTicketTypeEnName(airportExpressInfoDTO.getTicketTypeNameEn());
        return orderDTO;
    }

    @Override
    public CallPayDTO getCallPayInfo(Long orderId) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(Wrappers.<AirportExpressOrder>lambdaQuery()
                .eq(AirportExpressOrder::getId, orderId)
                .eq(AirportExpressOrder::getPaymentStatus, OrderPaymentStatus.UN_PAYMENT.getCode())
                .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(AirportExpressOrder::getId, AirportExpressOrder::getOrderNumber, AirportExpressOrder::getReceivableAmount,
                        AirportExpressOrder::getPayExpireDate, AirportExpressOrder::getSalesmanId, AirportExpressOrder::getPaymentStatus));
        if (airportExpressOrder == null) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        CallPayDTO callPayDTO = EntityUtil.copy(airportExpressOrder, CallPayDTO.class);
        callPayDTO.setOrderValidTime(airportExpressOrder.getPayExpireDate());
        callPayDTO.setTotalFee(airportExpressOrder.getReceivableAmount());
        callPayDTO.setCurrency(PayCurrency.HKD);
        callPayDTO.setSubject("机场快线订单支付");
        callPayDTO.setBody("机场快线订单支付");
        return callPayDTO;
    }

    @Override
    public Result<AirportExpressOrderAppInfoDTO> getInfo(Long id) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(new QueryWrapper<AirportExpressOrder>().lambda()
                .eq(AirportExpressOrder::getId, id)
                .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(AirportExpressOrder::getOrderNumber, AirportExpressOrder::getReceivableAmount, AirportExpressOrder::getAirportExpressId,
                        AirportExpressOrder::getEffectiveTime, AirportExpressOrder::getPayExpireDate, AirportExpressOrder::getAdultTicketNumber, AirportExpressOrder::getChildrenTicketNumber));
        AirportExpressOrderAppInfoDTO airportExpressOrderAppInfoDTO = EntityUtil.copy(airportExpressOrder, AirportExpressOrderAppInfoDTO.class);
        TicketNameDTO ticketNameDTO = airportExpressService.selectTicketNameById(airportExpressOrder.getAirportExpressId());
        airportExpressOrderAppInfoDTO.setTicketTypeNameCn(ticketNameDTO.getTicketTypeNameCn());
        airportExpressOrderAppInfoDTO.setTicketTypeNameEn(ticketNameDTO.getTicketTypeNameEn());
        return Result.success(airportExpressOrderAppInfoDTO);
    }

    @Override
    public Result<AirportExpressOrderAppQueryDTO> queryDetail(Long id) {
        AirportExpressOrder airportExpressOrder = airportExpressOrderMapper.selectOne(Wrappers.<AirportExpressOrder>lambdaQuery()
                .eq(AirportExpressOrder::getId, id)
                .eq(AirportExpressOrder::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(AirportExpressOrder::getId, AirportExpressOrder::getAirportExpressId,
                        AirportExpressOrder::getPaymentStatus, AirportExpressOrder::getReceivableAmount,
                        AirportExpressOrder::getOrderNumber, AirportExpressOrder::getInquiryNumber, AirportExpressOrder::getTicketTypeName,
                        AirportExpressOrder::getNumber, AirportExpressOrder::getAdultTicketNumber, AirportExpressOrder::getChildrenTicketNumber,
                        AirportExpressOrder::getAdultPrice, AirportExpressOrder::getChildrenPrice, AirportExpressOrder::getOrderAmount,
                        AirportExpressOrder::getUsingPoints, AirportExpressOrder::getContactName, AirportExpressOrder::getContactTitle,
                        AirportExpressOrder::getContactMobileAreaCode, AirportExpressOrder::getContactMobileAreaCode, AirportExpressOrder::getContactMobile, AirportExpressOrder::getContactEmail,
                        AirportExpressOrder::getEffectiveTime, AirportExpressOrder::getRemark, AirportExpressOrder::getPayExpireDate,
                        AirportExpressOrder::getGmtCreate));
        if (airportExpressOrder == null) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60002);
        }
        AirportExpressOrderAppQueryDTO airportExpressOrderQueryDTO = EntityUtil.copy(airportExpressOrder, AirportExpressOrderAppQueryDTO.class);
        // 查询应收金额
        AirportExpressOrderCollection airportExpressOrderCollection = airportExpressOrderCollectionMapper.selectOne(new QueryWrapper<AirportExpressOrderCollection>().lambda()
                .eq(AirportExpressOrderCollection::getOrderId, airportExpressOrder.getAirportExpressId())
                .eq(AirportExpressOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(AirportExpressOrderCollection::getStandardAmount));
        if (airportExpressOrderCollection != null) {
            airportExpressOrderQueryDTO.setReceivableAmount(airportExpressOrderCollection.getStandardAmount());
        }
        // 查询票种名称
        TicketNameDTO ticketNameDTO = airportExpressService.selectTicketNameById(airportExpressOrder.getAirportExpressId());
        airportExpressOrderQueryDTO.setTicketTypeNameCn(ticketNameDTO.getTicketTypeNameCn());
        airportExpressOrderQueryDTO.setTicketTypeNameEn(ticketNameDTO.getTicketTypeNameEn());
        // 查询港铁二维码票
        List<String> qrCodeUrlList = airportExpressOrderTouristMapper.selectObjs(new QueryWrapper<AirportExpressOrderTourist>().lambda()
                .eq(AirportExpressOrderTourist::getOrderId, id)
                .eq(AirportExpressOrderTourist::getIsDeleted, IsDeletedCode.NO.getCode())
                .select(AirportExpressOrderTourist::getThirdTicketQrCodeUrl))
                .stream().map(o -> (String) o).collect(Collectors.toList());
        airportExpressOrderQueryDTO.setQrCodeUrlList(qrCodeUrlList);
        // 构建订单状态
//        buildOrderStatus(airportExpressOrderQueryDTO);
//        buildAmount(airportExpressOrderQueryDTO);
//        airportExpressOrderQueryDTO.setBookingInformation(airportExpressInfoDTO.getBookingInformation());
//        if (airportExpressOrder.getUsingPoints() == null && airportExpressOrder.getCouponId() == null) {
//            airportExpressOrderQueryDTO.setEnableUnionPayOffer(1);
//        } else {
//            airportExpressOrderQueryDTO.setEnableUnionPayOffer(0);
//        }
        return Result.success(airportExpressOrderQueryDTO);
    }

    /**
     * 执行es上架
     *
     * @param airportExpressOrderUpLoadDTOS
     * @return
     */
    private Result up(List<AirportExpressOrderUpLoadDTO> airportExpressOrderUpLoadDTOS, LocalDateTime dateTime) {
        /*
         高级客户端上架方式，暂留
        BulkRequest bulkRequest = new BulkRequest();
        airportExpressOrderUpLoadDTOS.forEach(item -> {
            String jsonString = JSON.toJSONString(item);
            IndexRequest request = new IndexRequest(ElasticSearchConstant.AIR_EXPRESS_ORDER_DETAILS_INDEX)
                    .id(item.getId().toString())
                    .source(jsonString, XContentType.JSON);
            bulkRequest.add(request);
        });
        // 上架
        try {
            restHighLevelClient.bulk(bulkRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }*/
        // 上架数据
        airportExpressOrderUpLoadMapper.saveAll(airportExpressOrderUpLoadDTOS);

        // 标记更新时间
        redisTemplate.opsForValue().set(RedisConstants.AIR_EXPRESS_ORDER_DETAILS_UPDATE, JSON.toJSONString(dateTime));
        return Result.success();
    }

    /**
     * 构建es检索请求
     *
     * @param param
     * @return
     */
    private SearchRequest buildSearchRequset(AirportExpressOrderListReq param, List<Long> userList) {
        // 构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 1、构建bool - query
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // mustc
        if (null != param.getUserId()) {
            boolQuery.must(QueryBuilders.termsQuery("createId", userList));
        }

        // must - math - 订单号
        if (param.getOrderNumber() != null) {
            boolQuery.must(QueryBuilders.matchQuery("orderNumber", param.getOrderNumber()));
        }

        // filter - 过滤 - 票种名称
        if (param.getTicketTypeName() != null) {
            boolQuery.filter(QueryBuilders.termQuery("ticketTypeName", param.getTicketTypeName()));
        }

        //  filter - 过滤 - 支付状态
        if (param.getPaymentStatus() != null) {
            boolQuery.filter(QueryBuilders.termQuery("paymentStatus", param.getPaymentStatus()));
        }

        //  filter - 过滤 - 预订状态
        if (param.getScheduledStatus() != null) {
            boolQuery.filter(QueryBuilders.termQuery("scheduledStatus", param.getScheduledStatus()));
        }

        // filter - 过滤 - 联络人
        if (param.getContactName() != null) {
            boolQuery.filter(QueryBuilders.termQuery("contactName", param.getContactName()));
        }

        // filter - 过滤 - 订单来源
        if (param.getSource() != null) {
            boolQuery.filter(QueryBuilders.termQuery("source", param.getSource()));
        }

        // filter - 过滤 - 销售员
        if (param.getSalesmanName() != null) {
            boolQuery.filter(QueryBuilders.termQuery("salesmanName", param.getSalesmanName()));
        }

        // filter - 过滤 - 时间范围
        if (param.getFromGmtCreate() != null) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("gmtCreate");
            rangeQuery.gte(param.getFromGmtCreate());
            if (param.getToGmtCreate() == null) {
                rangeQuery.lte(param.getToGmtCreate());
            }
            boolQuery.filter(rangeQuery);
        }

        // 排序
        sourceBuilder.sort(new FieldSortBuilder("gmtCreate").order(SortOrder.DESC));

        // 分页
        sourceBuilder.from(param.getPageNo() == null ? 0 : (param.getPageNo() - 1) * param.getPageSize());
        sourceBuilder.size(param.getPageSize());

        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.TRIP_INDEX).source(sourceBuilder);
        return searchRequest;
    }

    /**
     * 构建，应收金额，实收金额，退款金额
     *
     * @param airportExpressOrderQueryDTO
     */
    private void buildAmount(AirportExpressOrderQueryDTO airportExpressOrderQueryDTO) {
        List<AirportExpressOrderRefundQueryDTO> airportExpressOrderRefundList = airportExpressOrderQueryDTO.getAirportExpressOrderRefundQueryDTOList();
        List<AirportExpressOrderCollectionQueryDTO> airportExpressOrderCollections = airportExpressOrderQueryDTO.getAirportExpressOrderCollectionQueryDTOList();
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal refundAmount = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(airportExpressOrderRefundList)) {
            for (AirportExpressOrderRefundQueryDTO refund : airportExpressOrderRefundList) {
                refundAmount = refundAmount.add(refund.getStandardAmount());
            }
        }
        if (CollectionUtils.isNotEmpty(airportExpressOrderCollections)) {
            for (AirportExpressOrderCollectionQueryDTO collection : airportExpressOrderCollections) {
                realAmount = realAmount.add(collection.getStandardAmount());
            }
        }
        //计算应收金额
        BigDecimal receivableAmount = airportExpressOrderQueryDTO.getOrderAmount().subtract(refundAmount);
        //计算实收金额
        realAmount = realAmount.subtract(refundAmount);
        airportExpressOrderQueryDTO.setReceivableAmount(receivableAmount);
        airportExpressOrderQueryDTO.setRealAmount(realAmount);
        airportExpressOrderQueryDTO.setRefundAmount(refundAmount);
    }

    /**
     * 构建订单状态
     *
     * @param airportExpressOrderQueryDTO
     */
    private void buildOrderStatus(AirportExpressOrderQueryDTO airportExpressOrderQueryDTO) {
        if (OrderPaymentStatus.UN_PAYMENT.getCode().equals(airportExpressOrderQueryDTO.getPaymentStatus())) {
            if (airportExpressOrderQueryDTO.getScheduledStatus() == null) {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.UN_PAYMENT.getCode());//待付款
            }
        } else if (Objects.equals(OrderPaymentStatus.ALREADY_PAYMENT.getCode(), airportExpressOrderQueryDTO.getPaymentStatus())) {
            if (Objects.equals(airportExpressOrderQueryDTO.getScheduledStatus(), OrderScheduledStatus.CONFIRM_RESERVE.getCode())) {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.CONFIRM_RESERVE.getCode());//待预订
            } else if (Objects.equals(OrderScheduledStatus.RESERVE_SUCCESS.getCode(), airportExpressOrderQueryDTO.getScheduledStatus())) {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.RESERVE_SUCCESS.getCode());//确认成功
            } else {
                airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());//确认失败
            }
        } else if (OrderPaymentStatus.ALREADY_CANCEL.getCode().equals(airportExpressOrderQueryDTO.getPaymentStatus())) {
            airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.ALREADY_CANCEL.getCode());//已取消
        } else {
            airportExpressOrderQueryDTO.setOrderStatus(OrderStatus.RESERVE_FAIL.getCode());//确认失败
        }
    }

    /**
     * 从redis获取数据的上次更新时间
     *
     * @return
     */
    private LocalDateTime getUpdateTime() {
        /*
        之前更新时间保存到es,现在调整到redis，先留着备用
        SearchRequest searchRequest = new SearchRequest(ElasticSearchConstant.AIR_EXPRESS_ORDER_DETAILS_UPDATE);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchRequest.source(searchSourceBuilder);

        try {
            SearchResponse search = restHighLevelClient.search(searchRequest, ElasticSearchConfiguration.COMMON_OPTIONS);
            SearchHits hits = search.getHits();
            if (hits != null) {
                for (SearchHit hit : hits) {
                    String s = hit.getSourceAsString();
                    return JSON.parseObject(s, LocalDateTime.class);
                }
            }
        } catch (IOException e) {
            log.error("【业务模块APP服務-查询es产品列表】异常", e);
            throw new BusinessException(SystemError.ES_IO_EXCEPTION_19004);
        }*/

        return JSON.parseObject((String) redisTemplate.opsForValue().get(RedisConstants.AIR_EXPRESS_HOME_UPDATE_TIME), LocalDateTime.class);
    }

    /**
     * 异步发送订单数据到个人中心
     *
     * @param orderId 订单Id
     */
    public void sendOrderToAppUser(Long orderId) {
        CompletableFuture.runAsync(() -> {
            try {
                MyAirportExpressOrderDTO orderDTO = buildEsOrderDTO(orderId);
                orderEsService.saveOrderToEs(orderDTO, SystemBusinessType.AIR_EXPRESS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 异步更新订单状态到个人中心
     */
    public void updateStatusToAppUser(Long orderId) {
        CompletableFuture.runAsync(() -> {
            try {
                AirportExpressOrder order = baseMapper.selectById(orderId);
                orderEsService.updateStatusToEs(order.getId(), SystemBusinessType.AIR_EXPRESS.getCode(),
                        null, order.getPaymentStatus(), order.getScheduledStatus(),
                        order.getCancelStatus());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}
